<?php

require_once ROOT . '/db/AdminEntity.php';
require_once ROOT . '/db/MenuEntity.php';
require_once ROOT . '/db/PageEntity.php';

final class Admin {
    private static $smarty;
    private static $url;
    private static $admin;

    public static function init(Smarty $smarty) {
        self::$smarty = $smarty;
        self::initAdminUser();
        self::$url = isset($_GET['url']) ? explode('/', $_GET['url']) :
                array();
        self::initTopMenu();
        self::initSubMenu();
        self::initCurrentHeading();
        self::initContent();
        self::initMessages();
    }

    public static function event($event) {
        self::initAdminUser();
        if (!self::$admin) {
            if ($event == 'login') {
                self::onLogin();
            } else {
                self::error('haveToBeLoggedIn');
            }
            return '';
        }
        $handler = 'on' . ucfirst($event);
        $reflection = new ReflectionClass('Admin');
        if ($reflection->hasMethod($handler)) {
            return $reflection->getMethod($handler)->invoke(null, '');
        } else {
            self::warning('cannotProcessEvent');
            return '';
        }
    }

    public static function onSearch() {
        return 'search/' . urlencode($_POST['search']) . '/' .
                (isset($_POST['pages']) ? 1 : 0) . '/' .
                (isset($_POST['menu']) ? 1 : 0) . '/' .
                (isset($_POST['admins']) ? 1 : 0) . '/';
    }

    public static function onAdminAdd() {
        if ($_POST['password'] != $_POST['checkPassword']) {
            self::error('passwordsNotSame');
            return 'admins/';
        }
        $admin = new AdminEntity(array(
            'login' => $_POST['login'],
            'password' => sha1($_POST['password'])
        ));
        try {
            Persistence::save($admin);
            self::confirm('adminAdded');
        } catch (Exception $e) {
            self::error('adminNotAdded');
            self::notice($e->getMessage());
        }
        return 'admins/';
    }

    public static function onAdminPassword() {
        if ($_POST['newPassword'] != $_POST['checkPassword']) {
            self::error('passwordsNotSame');
            return 'admins/';
        }
        $admin = Persistence::load('Admin', array(
            'login' => self::$admin,
            'password' => sha1($_POST['oldPassword'])
        ));
        if (empty($admin)) {
            self::error('incorrectOldPassword');
            return 'admins/';
        }
        $admin[0]->password = sha1($_POST['newPassword']);
        try {
            Persistence::save($admin[0]);
            self::confirm('passwordChanged');
        } catch (Exception $e) {
            self::error('passwordNotChanged');
            self::notice($e->getMessage());
        }
        return 'admins/';
    }

    public static function onDeleteMenu() {
        try {
            Persistence::delete('Menu', array('id' => (int) $_POST['id']));
            self::confirm('menuItemDeleted');
        } catch (Exception $e) {
            self::error('menuItemNotDeleted');
            self::notice($e->getMessage());
        }
        return 'menu/';
    }

    public static function onEditMenu() {
        try {
            $menu = Persistence::find('Menu', (int) $_POST['id']);
            $menu->href   = $_POST['href'];
            $menu->label  = $_POST['label'];
            $menu->parent = (int) $_POST['parent'];
            Persistence::save($menu);
            self::confirm('menuItemSaved');
        } catch (Exception $e) {
            self::error('menuItemNotSaved');
            self::notice($e->getMessage());
        }
        return 'menu/';
    }

    public static function onAddMenu() {
        $menu = new MenuEntity(array(
            'href'   => $_POST['href'],
            'label'  => $_POST['label'],
            'parent' => (int) $_POST['parent']
        ));
        try {
            Persistence::save($menu);
            self::confirm('menuItemCreated');
            if (isset($_POST['createPage'])) {
                $_POST['href'] = preg_replace('/\\/$/', '', $_POST['href']);
                $page = new PageEntity(array(
                    'url'     => $_POST['href'],
                    'title'   => $_POST['label'],
                    'content' => ''
                ));
                try {
                    Persistence::save($page);
                    self::confirm('adjacentPageCreated');
                    return 'pages/edit/' . $page->id . '/';
                } catch (Exception $e) {
                    self::error('adjacentPageNotCreated');
                    self::notice($e->getMessage());
                }
            }
        } catch (Exception $e) {
            self::error('menuItemNotCreated');
            self::notice($e->getMessage());
        }
        return 'menu/';
    }

    public static function onDeletePage() {
        try {
            Persistence::delete('Page', array('id' => (int) $_POST['id']));
            self::confirm('pageDeleted');
        } catch (Exception $e) {
            self::error('pageNotDeleted');
            self::notice($e->getMessage());
        }
        return '';
    }

    public static function onEditPage() {
        if (trim($_POST['url']) == '') {
            $url = iconv('UTF-8', 'ASCII//TRANSLIT', $_POST['title']);
            $url = preg_replace('/\\W+/', '-', strtolower($url));
            $url = preg_replace('/-+/', '-', $url);
            $url = preg_replace('/^-+/', '', $url);
            $_POST['url'] = preg_replace('/-+$/', '', $url);
        }
        if (isset($_POST['index'])) {
            $_POST['url'] = '';
        }
        
        $page = new PageEntity(array(
            'id'      => (int) $_POST['id'],
            'url'     => $_POST['url'],
            'title'   => $_POST['title'],
            'content' => $_POST['content']
        ));
        try {
            Persistence::save($page);
            self::confirm('pageSavedSuccessfully');
        } catch (Exception $e) {
            self::error('pageWasNotSaved');
            self::notice($e->getMessage());
        }
        return '';
    }

    public static function onCreatePage() {
        if (trim($_POST['url']) == '') {
            $url = iconv('UTF-8', 'ASCII//TRANSLIT', $_POST['title']);
            $url = preg_replace('/\\W+/', '-', strtolower($url));
            $url = preg_replace('/-+/', '-', $url);
            $url = preg_replace('/^-+/', '', $url);
            $_POST['url'] = preg_replace('/-+$/', '', $url);
        }
        if (isset($_POST['index'])) {
            $_POST['url'] = '';
        }
        
        $page = new PageEntity(array(
            'url'     => $_POST['url'],
            'title'   => $_POST['title'],
            'content' => $_POST['content']
        ));
        try {
            Persistence::save($page);
            self::confirm('pageCreated');
        } catch (Exception $e) {
            self::error('pageWasNotCreated');
            self::notice($e->getMessage());
        }
        return '';
    }

    public static function onLogout() {
        unset($_SESSION['admin']);
        return '';
    }

    private static function onLogin() {
        $check = Persistence::load('Admin', array(
            'login'    => $_POST['login'],
            'password' => sha1($_POST['password'])
        ));
        if (empty($check)) {
            self::error('loginUnsuccessful');
        } else {
            self::confirm('loginSuccessful');
            $_SESSION['admin'] = $check[0]->login;
        }
    }

    private static function initContent() {
        if (!self::$admin) {
            self::$smarty->assign('template', 'login');
            return;
        }
        if (!isset(self::$url[0])) {
            self::initPageList();
            return;
        }
        switch (self::$url[0]) {
            case 'pages':
                if (isset(self::$url[1]) && (self::$url[1] == 'add')) {
                    self::$smarty->assign('template', 'pageadd');
                } elseif (isset(self::$url[2]) && (self::$url[1] == 'edit')) {
                    self::initPageEdit(self::$url[2]);
                } else {
                    self::initPageList();
                }
                break;
            case 'menu':
                if (isset(self::$url[1]) && (self::$url[1] == 'add')) {
                    self::initMenuAdd();
                } elseif (isset(self::$url[2]) && (self::$url[1] == 'edit')) {
                    self::initMenuEdit(self::$url[2]);
                } else {
                    self::initMenuList();
                }
                break;
            case 'admins':
                if (isset(self::$url[1]) && (self::$url[1] == 'password')) {
                    self::$smarty->assign('template', 'adminpassword');
                } elseif (isset(self::$url[1]) && (self::$url[1] == 'add')) {
                    self::$smarty->assign('template', 'adminadd');
                } else {
                    self::initAdminsList();
                }
                break;
            case 'search':
                if (isset(self::$url[4])) {
                    self::search(self::$url[1], self::$url[2], self::$url[3],
                            self::$url[4]);
                }
                break;
        }
    }

    private static function search($phrase, $pages, $menu, $admins) {
        $result = array();
        $phrase = strtolower($phrase);
        if ($pages) {
            $items = dibi::query('SELECT [id], [title] FROM [Page] ' .
                    'WHERE LOWER([title]) LIKE %~like~', $phrase);
            foreach ($items as $page) {
                $page['edit'] = WEB_DIR . '/admin/pages/edit/' .
                        $page['id'] . '/';
                $page['name'] = $page['title'];
                $result[] = $page;
            }
        }
        if ($menu) {
            $items = dibi::query('SELECT [id], [label] FROM [Menu] ' .
                    'WHERE LOWER([label]) LIKE %~like~', $phrase);
            foreach ($items as $item) {
                $item['edit'] = WEB_DIR . '/admin/menu/edit/' .
                        $item['id'] . '/';
                $item['name'] = $item['label'];
                $result[] = $item;
            }
        }
        if ($admins) {
            $items = dibi::query('SELECT [login] FROM [Admin] ' .
                    'WHERE LOWER([login]) LIKE %~like~', $phrase);
            foreach ($items as $admin) {
                $admin['name'] = $admin['login'];
                $result[] = $admin;
            }
        }
        self::$smarty->assign('searchResults', $result);
        self::$smarty->assign('template', 'search');
    }

    private static function initAdminsList() {
        $admins = Persistence::load('Admin', array(), array('id'));
        foreach ($admins as &$admin) {
            $admin = $admin->dump();
        }
        self::$smarty->assign('administrators', $admins);
        self::$smarty->assign('template', 'adminslist');
    }

    private static function initMenuAdd() {
        $options = self::getMenuTreeOptions();
        self::$smarty->assign('items', $options);
        self::$smarty->assign('template', 'menuadd');
    }
    
    private static function initMenuEdit($id) {
        $item = Persistence::find('Menu', (int) $id);
        
        $options = self::getMenuTreeOptions();
        if ($item) {
            self::$smarty->assign($item->dump());
            self::$smarty->assign('template', 'menuedit');
            self::$smarty->assign('items', $options);
        } else {
            self::warning('menuItemNotFound');
        }
    }

    private static function initMenuList() {
        $tree = self::loadMenuTree();
        $menu = self::linearizeTree($tree);
        foreach ($menu as &$item) {
            $item['edit'] = WEB_DIR . "/admin/menu/edit/{$item['id']}/";
        }
        self::$smarty->assign('menuitems', $menu);
        self::$smarty->assign('template', 'menulist');
    }

    private static function initPageEdit($id) {
        $page = Persistence::find('Page', (int) $id);
        if ($page) {
            self::$smarty->assign($page->dump());
            self::$smarty->assign('template', 'pageedit');
        } else {
            self::warning('pageNotFound');
        }
    }

    private static function initPageList() {
        $pages = Persistence::load('Page', array(), array('id'));
        foreach ($pages as &$page) {
            $page = $page->dump();
            $page['edit'] = WEB_DIR . '/admin/pages/edit/' . $page['id'] . '/';
        }
        self::$smarty->assign('savedPages', $pages);
        self::$smarty->assign('template', 'pagelist');
    }

    private static function warning($msg) {
        if (!isset($_SESSION['msgs'])) {
            $_SESSION['msgs'] = array(
                'warnings' => array(),
                'notices' => array(),
                'confirms' => array(),
                'errors' => array()
            );
        }
        $_SESSION['msgs']['warnings'][] = Kernel::lang($msg);
    }

    private static function notice($msg) {
        if (!isset($_SESSION['msgs'])) {
            $_SESSION['msgs'] = array(
                'warnings' => array(),
                'notices' => array(),
                'confirms' => array(),
                'errors' => array()
            );
        }
        $_SESSION['msgs']['notices'][] = Kernel::lang($msg);
    }

    private static function confirm($msg) {
        if (!isset($_SESSION['msgs'])) {
            $_SESSION['msgs'] = array(
                'warnings' => array(),
                'notices' => array(),
                'confirms' => array(),
                'errors' => array()
            );
        }
        $_SESSION['msgs']['confirms'][] = Kernel::lang($msg);
    }

    private static function error($msg) {
        if (!isset($_SESSION['msgs'])) {
            $_SESSION['msgs'] = array(
                'warnings' => array(),
                'notices' => array(),
                'confirms' => array(),
                'errors' => array()
            );
        }
        $_SESSION['msgs']['errors'][] = Kernel::lang($msg);
    }

    private static function initMessages() {
        if (!isset($_SESSION['msgs'])) {
            return;
        }
        self::$smarty->assign($_SESSION['msgs']);
        $_SESSION['msgs'] = array(
            'warnings' => array(),
            'notices' => array(),
            'confirms' => array(),
            'errors' => array()
        );
    }

    private static function initCurrentHeading() {
        if (!self::$admin) {
            self::$smarty->assign('currentHeading',
                    Kernel::lang('loginToAdmin'));
            return;
        }
        $heading = '';
        if (isset(self::$url[0])) {
            switch (self::$url[0]) {
                case 'pages':
                    $heading = 'pages';
                    break;
                case 'menu':
                    $heading = 'menu';
                    break;
                case 'admins':
                    $heading = 'admins';
                    break;
                case 'search':
                    $heading = 'search';
                    break;
            }
        } else {
            $heading = 'pages';
        }
        self::$smarty->assign('currentHeading', Kernel::lang($heading));
    }

    private static function initSubMenu() {
        $items = array('pages', 'menu', 'admins');
        if (isset(self::$url[0])) {
            switch (self::$url[0]) {
                case 'menu':
                    $submenu = array(
                        array('label' => 'menuItems', 'link' => 'menu/'),
                        array('label' => 'addMenuItem', 'link' => 'menu/add/')
                    );
                    break;
                case 'admins':
                    $submenu = array(
                        array('label' => 'adminsList', 'link' => 'admins/'),
                        array('label' => 'editPassword', 'link' =>
                        'admins/password/'),
                        array('label' => 'addAdmin', 'link' => 'admins/add/')
                    );
                    break;
                default:
                    $submenu = array(
                        array('label' => 'pagesList', 'link' => ''),
                        array('label' => 'addPage', 'link' => 'pages/add/')
                    );
                    break;
            }
        } else {
            $submenu = array(
                array('label' => 'pagesList', 'link' => ''),
                array('label' => 'addPage', 'link' => 'pages/add/')
            );
        }
        foreach ($submenu as &$item) {
            $item['active'] = implode('/', self::$url) ==
                    substr($item['link'], 0, -1);
            $item['link'] = WEB_DIR . '/admin/' . $item['link'];
            $item['label'] = Kernel::lang($item['label']);
        }
        self::$smarty->assign('submenu', $submenu);
    }

    private static function initTopMenu() {
        $items = array('pages', 'menu', 'admins');
        if (isset(self::$url[0])) {
            self::$smarty->assign('topMenuActive',
                    array_search(self::$url[0], $items));
        } else {
            self::$smarty->assign('topMenuActive', 0);
        }
    }

    private static function initAdminUser() {
        self::$admin = isset($_SESSION['admin']) ? $_SESSION['admin'] : false;
        if (self::$smarty) {
            $params = array('admin' => self::$admin);
            self::$smarty->assign($params);
        }
    }

    private static function getMenuTreeOptions() {
        $tree = self::loadMenuTree();
        $linear = self::linearizeTree($tree);
        $result = array(0 => Kernel::lang('menuItemsRoot'));
        foreach ($linear as &$item) {
            $result[$item['id']] = "{$item['index']} - {$item['label']}";
        }
        return $result;
    }
    
    private static function linearizeTree($tree) {
        $result = array();
        foreach ($tree as &$item) {
            $result[] = $item;
            $result = array_merge($result, self::linearizeTree($item['sub']));
        }
        return $result;
    }
    
    private static function loadMenuTree($root = 0, $parentIndex = null) {
        $menu = Persistence::load('Menu', array('parent' => (int) $root),
                array('id'));
        $index = 1;
        foreach ($menu as &$item) {
            $item = $item->dump();
            $item['index'] = $parentIndex ? "$parentIndex.$index" : $index;
            $item['sub'] = self::loadMenuTree($item['id'], $item['index']);
            $index++;
        }
        return $menu;
    }
}
?>
